/* 
 * File:   Frame.cpp
 * Author: amouro-m
 * 
 * Created on 30 mai 2010, 18:51
 */

#include "Frame.h"

#include <QHBoxLayout>
#include <iostream>
#include <sstream>

#include "tbb/tick_count.h"

#include "FractalWindow.h"
#include "FractalMandel.hpp"
#include "FractalJulia.hpp"
#include "FractalPrinterInverse.h"
#include "FractalPrinterNormal.h"
#include "FractalInverseX.h"
#include "FractalInverseY.h"
#include "FiltreNB.hpp"
#include "FiltreRed.hpp"
#include "FiltreGreen.hpp"
#include "FiltreBlue.hpp"
#include "FractalCompute.hpp"
#include "LinearCompute.h"
#include "InformationPanel.h"
#include "TBBFiltre.h"
#include "Action.h"
#include "LinearFilter.h"
#include "BruitPerlin.h"
#include "FiltreFlou.h"

Frame::Frame(unsigned int width, unsigned int height, QWidget *parent):
QWidget(parent)
{

     _information_panel = new InformationPanel(this);
    _fractal_view_parallel = new FractalView(width, height/2, this);
    _result_panel_parallel = new ResultPanel(this);
    _fractal_view_linear = new FractalView(width, height/2, this);
    _result_panel_linear = new ResultPanel(this);
    _pipline = new tbb::pipeline();
   
    QHBoxLayout *layout_big_h = new QHBoxLayout;
    QHBoxLayout *layout_parallel = new QHBoxLayout;
    QHBoxLayout *layout_linear = new QHBoxLayout;
    QVBoxLayout *layout_big_v = new QVBoxLayout;

    layout_parallel->addWidget(_fractal_view_parallel);
    layout_parallel->addWidget(_result_panel_parallel);

    layout_linear->addWidget(_fractal_view_linear);
    layout_linear->addWidget(_result_panel_linear);

    layout_big_v->addLayout(layout_parallel);
    layout_big_v->addLayout(layout_linear);

    layout_big_h->addWidget(_information_panel);
    layout_big_h->addLayout(layout_big_v);
    setLayout(layout_big_h);

    connect(_information_panel->_qButton, SIGNAL(clicked()), this, SLOT(compute()));
}

Frame::~Frame()
{
    delete _result_panel_parallel;
    delete _fractal_view_parallel;
    delete _result_panel_linear;
    delete _fractal_view_linear;
    delete _information_panel;
}

FractalView*
Frame::get_fractal_view() const
{
    return _fractal_view_parallel;
}

ResultPanel*
Frame::get_chrono() const
{
    return _result_panel_parallel;
}

void
Frame::set_fractal(Fractal* fractal)
{
    if(_fractal_view_linear->get_fractal_printer()->get_fractal() != NULL)
        delete _fractal_view_linear->get_fractal_printer()->get_fractal();
    _fractal_view_parallel->set_fractal(fractal);
    _fractal_view_linear->set_fractal(fractal);
    this->apply_fractal();
}

void
Frame::set_fractal_julia()
{
    this->set_fractal(new FractalJulia(1000, 0.382, 0.147));
}

void
Frame::set_bruitdeperlin()
{
    int width = _fractal_view_linear->get_fractal_printer()->get_width();
    int heigth = _fractal_view_linear->get_fractal_printer()->get_height();
    this->set_fractal(new BruitPerlin(width, heigth, 0.5, 4, 4, 0, width, 0, heigth));
}


void
Frame::set_fractal_mendel()
{
    this->set_fractal(new FractalMandel(1000));
}

void
Frame::set_printer_normal()
{
    _fractal_view_linear->set_fractal_printer(new FractalPrinterNormal(_fractal_view_linear->get_area()));
    _fractal_view_parallel->set_fractal_printer(new FractalPrinterNormal(_fractal_view_parallel->get_area()));
}

void
Frame::set_printer_inversex()
{
    _fractal_view_linear->set_fractal_printer(new FractalInverseX(_fractal_view_linear->get_area()));
    _fractal_view_parallel->set_fractal_printer(new FractalInverseX(_fractal_view_parallel->get_area()));
}

void
Frame::set_printer_inversey()
{
    _fractal_view_linear->set_fractal_printer(new FractalInverseY(_fractal_view_linear->get_area()));
    _fractal_view_parallel->set_fractal_printer(new FractalInverseY(_fractal_view_parallel->get_area()));
}

void
Frame::set_printer_inversexy()
{
    _fractal_view_linear->set_fractal_printer(new FractalPrinterInverse(_fractal_view_linear->get_area()));
    _fractal_view_parallel->set_fractal_printer(new FractalPrinterInverse(_fractal_view_parallel->get_area()));
}

void
Frame::set_filtre_NB()
{
    Filtre* filtre = new FiltreNB;
    this->add_action(filtre);
}

void
Frame::set_filtre_Red()
{
    Filtre* filtre = new FiltreRed;
    this->add_action(filtre);
}

void
Frame::set_filtre_Green()
{
    Filtre& filtre = *new FiltreGreen;
    this->add_action(&filtre);
}

void
Frame::set_filtre_Blue()
{
    Filtre* filtre = new FiltreBlue;
    this->add_action(filtre);
}

void
Frame::set_filtre_Flou()
{
    Filtre* filtre = new FiltreFlou;
    this->add_action(filtre);
}

void
Frame::apply_fractal()
{
    FractalCompute::compute(_fractal_view_parallel->get_fractal_printer(), _result_panel_parallel);
    LinearCompute::compute(_fractal_view_linear->get_fractal_printer(), _result_panel_linear);
}

void
Frame::add_action(Computable* item)
{
    _information_panel->add_computable(item);
    _pipline->add_filter(* new TBBFiltre(item, _fractal_view_parallel->get_fractal_printer(), _result_panel_parallel));
    _linear_filter_list.push_back(new LinearFilter(item, _fractal_view_linear->get_fractal_printer(), _result_panel_linear));
}

void
Frame::compute()
{    

    /*
     * Parallel
     */
    _result_panel_parallel->reset();
    tbb::tick_count start, end;
    start = tbb::tick_count::now();

    _pipline->run(8);
    _pipline->clear();

    end = tbb::tick_count::now();
    tbb::tick_count::interval_t interval = (end - start);
    std::ostringstream parallel_os (std::ostringstream::out);
    parallel_os << "Fin parallel" << ": " << interval.seconds() << " s";
    std::string string(parallel_os.str());
    _result_panel_parallel->add_item(string.c_str());

    /*
     * Linear
     */
    _result_panel_linear->reset();
    start = tbb::tick_count::now();
    std::vector<LinearFilter*>::iterator filter;
    for (filter = _linear_filter_list.begin(); filter < _linear_filter_list.end(); ++filter)
        (*filter)->compute();
    end = tbb::tick_count::now();
    interval = (end - start);
    std::ostringstream linear_os (std::ostringstream::out);
    linear_os << "Fin lineaire" << ": " << interval.seconds() << " s";
    string = linear_os.str();
    _result_panel_linear->add_item(string.c_str());
    _linear_filter_list.clear();

    _information_panel->_qListWidget->clear();
}